package com.example.administrator.gplineview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2017/4/13.
 */

public class CstView extends View {

    private Paint mDefaultPaint;
    private int mHeight;
    private int mWidth;
    private float mTextHeight;
    private float mRealHeight;
    private float mRealWidth;
    private float mEveryHeight;
    private float mEveryWidth;
    private List<List<Point>> mPointsList;      //走势图坐标集合
    private List<Paint> mPaints;                //画笔集合
    private List<Path> mPaths;                  //走势图路径集合
    private int index;                          //设置当前走势图点的个数
    private float mTouchX;                      //触摸的点的坐标
    private int mIndex;
    private boolean mShowAnim;                  //走势图是否动画效果展示出来
    private float mXLoc = -1;
    private int mXLineNum;                       //和x轴平行的刻度线的数量
    private int mYLineNum;                       //和y轴平行的刻度线的数量
    private int mStartX;                         //原点x值
    private int mStartY;                         //原点y值
    private int mEndX;                           //x轴最大值
    private int mEndY;                           //y轴最大值
    private List<String> mLeftStrs;             //左边的文字
    private List<String> mRightStrs;            //右边的文字
    private List<String> mBottomStrs;            //底部的文字
    private float mLeftStrWidth;                  //左边文字宽度
    private float mRightStrWidth;                    //右边文字宽度
    private boolean isInArea;                   //点击事件是否在区域内部
    private List<Point> mPoints;
    private Path mPath;
    private Paint mPaint;
    private Paint mVerticalPaint;
    private float mEveryLeftHeight;
    private float mEveryRightHeight;
    private boolean isFirst;
    private Paint mWhiteFullPaint;          //白色实心画笔

    public CstView(Context context) {
        this(context, null);
    }

    public CstView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CstView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        mDefaultPaint = new Paint();
        mVerticalPaint = new Paint();
        mWhiteFullPaint = new Paint();
        mDefaultPaint.setColor(Color.WHITE);
        mVerticalPaint.setColor(Color.RED);
        mWhiteFullPaint.setColor(Color.WHITE);
        mDefaultPaint.setAntiAlias(true);
        mVerticalPaint.setAntiAlias(true);
        mWhiteFullPaint.setAntiAlias(true);
        mDefaultPaint.setTextSize(DensityUtils.sp2px(context, 11));
        mVerticalPaint.setTextSize(DensityUtils.sp2px(context, 11));
        mWhiteFullPaint.setTextSize(DensityUtils.sp2px(context, 11));
        mTextHeight = mDefaultPaint.descent() - mDefaultPaint.ascent();

        mPaints = new ArrayList<>();
        mPointsList = new ArrayList<>();
        mPaths = new ArrayList<>();
        mRightStrs = new ArrayList<>();
        mLeftStrs = new ArrayList<>();
        mBottomStrs = new ArrayList<>();

        mPath = new Path();
    }

    /**
     * 设置默认的画笔颜色
     * @param color
     */
    public void setDefaultPaintColor(int color){
        mDefaultPaint.setColor(color);
    }

    /**
     * 设置垂直画笔颜色
     * @param color
     */
    public void setVerticalPaintColor(int color){
        mVerticalPaint.setColor(color);
    }

    /**
     * 设置默认画笔size
     * @param size
     */
    public void setDefaultPaintTextSize(int size){
        mDefaultPaint.setTextSize(DensityUtils.sp2px(getContext(),size));
    }

    /**
     * 设置垂直画笔size
     * @param size
     */
    public void setVerticalPaintSize(int size){
        mDefaultPaint.setTextSize(DensityUtils.sp2px(getContext(),size));
    }

    @Override
    protected void onDraw(final Canvas canvas) {
        super.onDraw(canvas);
        if (mXLineNum == 0) return;
        mHeight = getMeasuredHeight();
        mWidth = getMeasuredWidth();
        mEveryHeight = mHeight / (mXLineNum + 1);
        mRealHeight = mEveryHeight * (mXLineNum - 1);
        if (!mLeftStrs.isEmpty()) mEveryLeftHeight = mRealHeight / (mLeftStrs.size() - 1);
        if (!mRightStrs.isEmpty()) mEveryRightHeight = mRealHeight / (mRightStrs.size() - 1);
        mLeftStrWidth = getStringWidth(mLeftStrs, mDefaultPaint) + DensityUtils.dp2px(getContext(), 4);
        mRightStrWidth = getStringWidth(mRightStrs, mDefaultPaint) + DensityUtils.dp2px(getContext(), 4);
        mRealWidth = mWidth - mLeftStrWidth - mRightStrWidth;
        if (!mBottomStrs.isEmpty())
            mEveryWidth = mBottomStrs.isEmpty() ? 0 : mRealWidth / (mBottomStrs.size());
        //画平行x的直线
        for (int i = 0; i < mXLineNum; i++) {
            canvas.drawLine(mLeftStrWidth, mEveryHeight * (i + 0.5f), mWidth - mRightStrWidth, mEveryHeight * (i + 0.5f), mDefaultPaint);
        }
        //画左边的文字
        for (int i = 0; i < mLeftStrs.size(); i++) {
            canvas.drawText(mLeftStrs.get(i), mLeftStrWidth - DensityUtils.dp2px(getContext(), 2) - getTextWidth(mDefaultPaint, mLeftStrs.get(i)), mEveryLeftHeight * (mLeftStrs.size() - 1 - i) + mEveryHeight * 0.5f + mTextHeight / 3f, mDefaultPaint);
        }
        //画右边的文字
        for (int i = 0; i < mRightStrs.size(); i++) {
            canvas.drawText(mRightStrs.get(i), mWidth - mRightStrWidth + DensityUtils.dp2px(getContext(), 2), mEveryRightHeight * (mRightStrs.size() - 1 - i) + mEveryHeight * 0.5f + mTextHeight / 3, mDefaultPaint);
        }
        //画下边的文字
        for (int i = 0; i < mBottomStrs.size(); i++) {
            canvas.drawText(mBottomStrs.get(i), mEveryWidth * i + mLeftStrWidth - getTextWidth(mDefaultPaint, mBottomStrs.get(i)) / 2, mHeight - 1.5f * mEveryHeight + mTextHeight, mDefaultPaint);
        }
        //画走势图
        for (int i = 0; i < mPointsList.size(); i++) {
            mPoints = mPointsList.get(i);
            mPaint = mPaints.get(i);
//            if (index > mPoints.size()) index = mPoints.size();
            for (int j = 0; j < index; j++) {
                if (j >= mPoints.size()) break;
                mPoints.get(j).setxLoc(getPointWidth(mPoints.get(j).getXVal()));
                mPoints.get(j).setyLoc(getPointHeight(mPoints.get(j).getYVal()));
                if (j == 0) {
                    mPath.moveTo(getPointWidth(mPoints.get(j).getXVal()), getPointHeight(mPoints.get(j).getYVal()));
                } else {
                    mPath.lineTo(getPointWidth(mPoints.get(j).getXVal()), getPointHeight(mPoints.get(j).getYVal()));
                }
            }
            canvas.drawPath(mPath, mPaint);
            mPath.reset();
        }
        //画垂直线
        if (mXLoc != -1) {
            for (int i = 0; i < mPointsList.size(); i++) {
                if (mPointsList.get(i).size() != getMaxSize()){
                    continue;
                }
                if (mIndex != -1) {
                    canvas.drawCircle(mPointsList.get(i).get(mIndex).getxLoc(), mPointsList.get(i).get(mIndex).getyLoc(), 10f, mWhiteFullPaint);
                    canvas.drawCircle(mPointsList.get(i).get(mIndex).getxLoc(), mPointsList.get(i).get(mIndex).getyLoc(), 10f, mPaints.get(i));
                }
            }
            canvas.drawLine(mXLoc, mEveryHeight * 0.5f, mXLoc, mEveryHeight * (-0.5f + mXLineNum), mVerticalPaint);
        }
        if (mShowAnim){
            postDelayed(action,100);
        }
    }

    private Runnable action = new Runnable() {
        @Override
        public void run() {
            index++;
            if (index <= getMaxSize()) {
                postInvalidate();
                postDelayed(this, 100);
            }
        }
    };

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mTouchX = event.getX();
        mIndex = getXIndex(mTouchX);
        if (mIndex != -1) setXLoc(mPointsList.get(0).get(mIndex == -1 ? 0 : mIndex).getxLoc());
        else {
            mXLoc = -1;
            postInvalidate();
        }
        return true;
    }

    /**
     * 测量文字宽度，从多个文字中获取最大值
     *
     * @param strs
     * @param paint
     * @return
     */
    private float getStringWidth(List<String> strs, Paint paint) {
        if (strs.isEmpty()) return 0;
        float width = 0;
        for (int i = 0; i < strs.size(); i++) {
            width = Math.max(width, getTextWidth(paint, strs.get(i)));
        }
        return width;
    }

    /**
     * 根据画笔测量出字体的高度
     *
     * @param paint
     * @return
     */
    private float getTextHeight(Paint paint) {
        return paint.descent() - paint.ascent();
    }

    /**
     * 根据画笔测量出字体宽度
     *
     * @param paint
     * @param text
     * @return
     */
    private float getTextWidth(Paint paint, String text) {
        return paint.measureText(text);
    }

    /**
     * 修改触摸点横坐标
     *
     * @param xLoc
     */
    private void setXLoc(float xLoc) {
        mXLoc = xLoc;
        postInvalidate();
    }

    /**
     * 设置坐标以及xy轴的值范围
     *
     * @param startX  原点x的值
     * @param startY  原点y的值
     * @param targetX x轴最大值
     * @param targetY y轴最大值
     */
    public void setXYValue(int startX, int startY, int targetX, int targetY) {
        mStartX = startX;
        mStartY = startY;
        mEndX = targetX;
        mEndY = targetY;
    }

    /**
     * 设置平行于轴的线的数量
     *
     * @param xNum 平行x轴的线的数量
     * @param yNum 平行y的线的数量
     */
    public void setXYLineNum(int xNum, int yNum) {
        mXLineNum = xNum;
        mYLineNum = yNum;
    }

    /**
     * 初始化view的一些数据
     * @param leftStrs
     * @param rightStrs
     * @param bottomStrs
     * @param xNum
     * @param yNum
     */
    public void setData(List<String> leftStrs, List<String> rightStrs, List<String> bottomStrs, int xNum, int yNum) {
        setXYLineNum(xNum, yNum);
        mLeftStrs = leftStrs;
        mRightStrs = rightStrs;
        mBottomStrs = bottomStrs;
        postInvalidate();
    }

    /**
     * 添加一条走势曲线
     *
     * @param color  走势曲线的颜色
     * @param points 走势曲线上点的集合
     */
    public void addLine(int color, List<Point> points) {
        Paint paint = new Paint();      //走势图画笔
        paint.setColor(color);
        paint.setAntiAlias(true);
        paint.setTextSize(DensityUtils.sp2px(getContext(), 14));
        paint.setStyle(Paint.Style.STROKE);
        mPaints.add(paint);

        Path path = new Path();
        mPaths.add(path);

        mPointsList.add(points);
        index = getMaxSize();
        postInvalidate();
    }

    private int getMaxSize(){
        int num = 0;
        for (int i = 0; i < mPointsList.size(); i++) {
            num = Math.max(num,mPointsList.get(i).size());
        }
        return num;
    }


    /**
     * 根据纵坐标上的值确定点的坐标
     * @param height    此处代表的y方向的值（并非坐标，比如100元）
     * @return
     */
    public float getPointHeight(float height) {
        if (height > mEndY || height < mStartY) {
            return -10;
        }
        return mRealHeight * (mEndY - height) / (mEndY - mStartY) + mEveryHeight * 0.5f;
    }

    /**
     * 根据横坐标上的值确定点的坐标
     * @param width     代表x方向上的值，比如（起点2月1号表示0，则2月10号表示9），并非坐标
     * @return
     */
    public float getPointWidth(float width) {
        if (width < mStartX || width > mEndX) {
            return -10;
        }
        return mRealWidth * width / (mEndX - mStartX) + mLeftStrWidth;
    }

    /**
     * 获取集合中里触摸点最近的点的横坐标
     *
     * @param xVal 触摸点的横坐标
     * @return
     */
    private int getXIndex(float xVal) {
        if (mPointsList.isEmpty()) return -1;
        List<Point> points = mPointsList.get(0);
        int left = 0;
        int right = points.size() - 1;
        int mid = getMid(left, right);
        int temp;
        if (xVal < points.get(left).getxLoc() || xVal > points.get(right).getxLoc()) {
            return -1;
        }
        while (left != mid) {
            temp = mid;
            if (xVal < points.get(mid).getxLoc()) {
                mid = getMid(left, mid);
                right = temp;
            } else {
                mid = getMid(mid, right);
                left = temp;
            }
            if (left + 1 == right) {
                if (Math.abs(points.get(left).getxLoc() - xVal) > Math.abs(points.get(right).getxLoc() - xVal)) {
                    left = right;
                }
                break;
            }
        }
        return left;
    }

    public void setShowAnim(boolean showAnim){
        mShowAnim = showAnim;
        index = 0;
    }

    private int getMid(int left, int right) {
        return (left + right) / 2;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        ViewGroup.LayoutParams lp = getLayoutParams();
        if (lp.width != ViewGroup.LayoutParams.MATCH_PARENT) {
            widthSize = (int) (widthSize * MyApplication.mScreenWidth / 320.0);
        }
        if (lp.height != ViewGroup.LayoutParams.MATCH_PARENT) {
            heightSize = (int) (heightSize * MyApplication.mScreenWidth / 480.0);
        }
        widthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}
